package com.yj.text_pixel.util;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.os.Build;
import android.util.Log;

import com.yj.text_pixel.bean.TextBean;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Painter {
    private static final String TAG = "Painter";
    private Painter(){};
    private static Painter painter;
    public static Painter instance(){
        if(painter == null){
            synchronized (Painter.class){
                painter = new Painter();
            }
        }
        return painter;
    }

    private Paint paint;
    private List<Integer> emptyList;

    public void init(Context context){
        emptyList = new ArrayList<>();

        // Load the custom font from assets
        Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/new_song.ttc");

        // set up paint
        paint = new Paint();
        paint.setAntiAlias(false);  // Disable anti-aliasing
        paint.setAlpha(255); // Set fully opaque
        paint.setTypeface(typeface); // set typeface
//        paint.setTextAlign(Paint.Align.CENTER);
    }

    public HashMap<String, Object> getTextColors(int width, int height,
                                 List<TextBean> textBeanList,
                                 int fontSize,
                                 int maxFrames,
                                 int maxLines,
                                 boolean continuousPaint,
                                 boolean horizontalCenter
    ){
        Bitmap bitmap = null;
        try {
            if(textBeanList.isEmpty()){
                return null;
            }
            Log.d(TAG, "before fontSize "+fontSize);
            fontSize = (int) adjustFontSize("看", height, fontSize);
            Log.d(TAG, "after fontSize "+fontSize);
//            Log.d(TAG, ""+textBeanList);
            float[] arr = preCalculateWidth(textBeanList, fontSize, width, maxLines, continuousPaint);
            float totalWidth = arr[0];
            float totalHeight = arr[1];
            Log.d(TAG, String.format("totalWidth %f totalHeight %f", totalWidth, totalHeight));
            int frames = (int) Math.ceil(totalWidth / width);
            frames = Math.min(frames, maxFrames);
            int canvasWidth = width * frames;
            Log.d(TAG, String.format("canvas width %d height %d", canvasWidth, height));
            bitmap = createBitmap(canvasWidth, width, height, textBeanList, fontSize,
                    totalHeight, maxLines, continuousPaint, horizontalCenter);
            List<Integer> colors = getBitmapPixels(bitmap, width, frames);
            HashMap<String, Object> map = new HashMap<>();
            map.put("colors", colors);
            map.put("maxLines", totalHeight / fontSize);
            return map;
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {
            if(bitmap != null){
                bitmap.recycle();
            }
        }
    }

    private float adjustFontSize(String text, int height, int fontSize){
//        String text = textBean.getCharacter();
        paint.setTextSize(fontSize);
//        paint.setColor(textBean.getColorValue().intValue());
        paint.setColor(Color.RED);

        Path textPath = new Path();
        paint.getTextPath(text, 0, text.length(), 0.0f, 0.0f, textPath);
        RectF boundsPath = new RectF();
        textPath.computeBounds(boundsPath, true);
        float textHeight = boundsPath.height();
        Log.d(TAG, "fontSize: "+fontSize+" textHeight: "+textHeight+" height: "+height);
        while (textHeight > height){
            paint.setTextSize(--fontSize);

            textPath = new Path();
            paint.getTextPath(text, 0, text.length(), 0.0f, 0.0f, textPath);
            boundsPath = new RectF();
            textPath.computeBounds(boundsPath, true);
            textHeight = boundsPath.height();
            Log.d(TAG, "fontSize: "+fontSize+" textHeight: "+textHeight+" height: "+height);
        }
        return fontSize;
    }

    /**
     * 预计算绘制后 bitmap 的宽度和高度
     * @param textBeanList
     * @param fontSize
     * @param width
     * @param maxLines
     * @return
     */
    private float[] preCalculateWidth(List<TextBean> textBeanList, int fontSize, int width,
                                      int maxLines,
                                      boolean continuousPaint){
        float[] arr = new float[]{0, fontSize};
        paint.setTextSize(fontSize);

        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        float baseline = (fontMetrics.descent - fontMetrics.ascent) / 2 - fontMetrics.descent;
        Log.d(TAG, String.format("fontMetrics leading %f ascent %f top %f bottom %f descent %f " +
                        "baseline %f",
                fontMetrics.leading, fontMetrics.ascent, fontMetrics.top,
                fontMetrics.bottom, fontMetrics.descent, baseline));



        int len = textBeanList.size();
        int frame = 1;
        int line = 1;
        float offsetX = 0;
        for(int i = 0; i < len; i++){
            paint.setColor(textBeanList.get(i).getColorValue().intValue());


//            if(arr[1] == 0){
//
//                String text = "看";
//
//                Path textPath = new Path();
//                paint.getTextPath(text, 0, text.length(), 0.0f, 0.0f, textPath);
//                RectF boundsPath = new RectF();
//                textPath.computeBounds(boundsPath, true);
//                arr[1] = boundsPath.height();
//
//                Rect rect = new Rect();
//                paint.getTextBounds(text, 0, text.length(), rect);
//                Log.d(TAG, String.format("textBound width %d height %d", rect.width(), rect.height()));
//            }

            String text = textBeanList.get(i).getCharacter();

            float textWidth = paint.measureText(text);

            if(offsetX + textWidth > (width * frame)){
                if(line < maxLines){
                    offsetX = (frame - 1) * width + textWidth;
                    line += 1;

                    arr[1] = Math.max(arr[1], line * fontSize);
                }else{// next frame

                    if(continuousPaint && maxLines == 1){ // single line
                        offsetX += textWidth;
                        arr[0] += textWidth;
                    }else{
                        line = 1;
                        float between = (width * frame) - offsetX;
                        offsetX += between + textWidth;
                        arr[0] += between + textWidth;
                    }

                    frame += 1;
                }
            }else{
                offsetX += textWidth;
                if(line == 1){
                    arr[0] += textWidth;
                }

            }


        }



        return arr;
    }

    private float preCalculateLineWidth(List<TextBean> tempList, float width){
        float sum = 0;
        for(TextBean textBean: tempList){
            paint.setColor(textBean.getColorValue().intValue());
            float textWidth = paint.measureText(textBean.getCharacter());
            if(sum + textWidth > width){ // overflow
                return sum;
            }
            sum += textWidth;
        }
        return sum;
    }

    private Bitmap createBitmap(int canvasWidth, int width, int height, List<TextBean> textBeanList,
                                int fontSize, float totalHeight, int maxLines,
                                boolean continuousPaint, boolean horizontalCenter){


        // Step 1: Create a Bitmap and Canvas
        Bitmap bitmap = Bitmap.createBitmap(canvasWidth, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);

        // Step 2: Set up Paint for text
        paint.setTextSize(fontSize);

        Paint.FontMetrics fontMetrics = paint.getFontMetrics();

        int len = textBeanList.size();
        float startOffsetY = fontSize - fontMetrics.leading + ((height - totalHeight) / 2);



        float offsetX = 0;

        // for first line
        float lineWidth = preCalculateLineWidth(textBeanList.subList(0, len), width);

//        Log.d(TAG, "lineWidth "+lineWidth );
        if(horizontalCenter && (lineWidth < width)){ // not full line width
            offsetX += (width - lineWidth) / 2;
//            Log.d(TAG, "fistLine "+offsetX);
        }

//        float textHeight = (float) Math.floor(totalHeight);
//        float offsetY = (float) (height - fontSize) / 2;
//        Log.d(TAG, String.format("totalHeight %f textHeight %f height %d fontSize %d offsetY %f",
//                totalHeight, textHeight, height, fontSize, offsetY));
//        offsetY += textHeight;
        float offsetY = startOffsetY;

//        Log.d(TAG, "offsetY "+offsetY);

        int frame = 1;
        int line = 1;
        for(int i = 0; i < len; i++){
            paint.setColor(textBeanList.get(i).getColorValue().intValue());

            String text = textBeanList.get(i).getCharacter();


            float textWidth = paint.measureText(text);
//            Log.d(TAG, String.format("offsetX %f textWidth %f about reach %f limit %d",
//                    offsetX, textWidth,
//                    (offsetX + textWidth),
//                    (width * frame))
//            );
            if(offsetX + textWidth > (width * frame)){ // need to switch line
                if(line < maxLines){

                    offsetX = (frame - 1) * width;

                    // next line
                    lineWidth = preCalculateLineWidth(textBeanList.subList(i, len), width);

                    if(horizontalCenter && (lineWidth < width)){// not full line width
                        offsetX += (width - lineWidth) / 2;
                    }


                    offsetY += fontSize;
                    canvas.drawText(text, offsetX, offsetY, paint);
                    offsetX += textWidth;
                    line += 1;
                }else{ // next frame



                    if(continuousPaint && maxLines == 1){// single line
                        canvas.drawText(text, offsetX, offsetY, paint);
                        offsetX += textWidth;
                    }else{
                        line = 1;
                        offsetY = startOffsetY;
                        float between = (width * frame) - offsetX;
//                Log.d(TAG, "between "+between);
                        offsetX += between;
//                Log.d(TAG, "offsetX "+offsetX);

                        // next frame first line
                        lineWidth = preCalculateLineWidth(textBeanList.subList(i, len), width);

                        if(horizontalCenter && (lineWidth < width)){ // not full line width
                            offsetX += (width - lineWidth) / 2;
                        }

                        // Step 3: Draw text onto the Canvas
                        canvas.drawText(text, offsetX, offsetY, paint);
                        offsetX += textWidth;
                    }

                    frame += 1;
                }

            }else{
                // Step 3: Draw text onto the Canvas
                canvas.drawText(text, offsetX, offsetY, paint);
                offsetX += textWidth;
            }



        }


        return bitmap;
    }

    private List<Integer> getBitmapPixels(Bitmap bitmap, int frameWidth, int frames) {

        List<Integer> colors = new ArrayList<>();

        int width = bitmap.getWidth();
        int height = bitmap.getHeight();

        Log.d(TAG, String.format("bitmap width %d height %d frameWidth %d frames %d", width, height, frameWidth, frames));

        for(int f = 0; f < frames; f++){
            // Step 4: Loop through each pixel in the bitmap
            for (int y = 0; y < height; y++) {
                for (int x = f * frameWidth; x < (f + 1) *frameWidth; x++) {
                    //                Log.d(TAG,  "x: "+ x +" y: "+y);
                    int color = bitmap.getPixel(x, y);
                    // Now, color holds the ARGB color of the pixel at (x, y)
                    // You can process this color as needed
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                        colors.add(color);
                    }
                }
            }

        }







        return colors;
    }

}
